#include "com_sct_rtsp_RTSPJni.h"

#include "sct/core/common.h"
#include "sct/core/mutex.h"
#include "sct/core/thread.h"

#include "sct/rtspclient/rtspclientinterface.h"

using namespace sct;

class CMediaSource:public CRTSPClientCallback, public CThreadCallBack
{
private:
	class CDataItem
	{
	public:
		int64_t pts;
		uint8_t * data;
		uint32_t len;
		uint32_t drop_frame_pre;

		static void freeDataItem(CDataItem * p)
		{
			SCT_DELETE_ARRAY(p->data);
			SCT_DELETE(p);
		}
	};

public:
	virtual void onRecvData(CRTSPClientInterface* caller,
				const void* d, const int len,
				const CRTSPClientInterface::CBlockInfo & info)
	{
		if(info.type == CRTSPServerInterface::TS)
		{
			CAutoLock locker(mMutex);

			int64_t maxDelay = 3000000;

			if(!mData.empty())
			{
				int64_t firstpts = mData.front()->pts;

				///fixme: pts value never wrap to 0
				firstpts = info.pts - firstpts;

				if(firstpts < 0) firstpts = -firstpts;

				if(firstpts > maxDelay)
				{
					//SCT_LOG("%lld %lld", firstpts, maxDelay);
					CDataItem::freeDataItem(mData.front());
					mData.pop_front();
				}
			}

			CDataItem * item = new CDataItem;
			item->data = new uint8_t[len];
			memcpy(item->data, d, len);
			item->len = len;
			item->pts = info.pts;
			item->drop_frame_pre = 0;

			mData.push_back(item);
		}
		else
		{
			SCT_LOGD();
		}
	}

	CMediaSource():mRTSPClient(NULL), mMutex(NULL),
			mThd(NULL), mState(0)
	{
		mMutex = new CMutex;

		mRTSPClient = CRTSPClientInterface::create("rtspclient");
		mRTSPClient->setServerUrl("rtsp://192.168.1.67:8554/live");
		mRTSPClient->addCallback(this);

		mState = 1;
//		pthread_create(&mThd, NULL, rtsp, this);
		mThd = new CThread("rtsp recv thread");
		mThd->addCallback(this);
		mThd->start();
	}

	virtual ~CMediaSource()
	{
		mState = 0;
//		pthread_join(mThd, NULL);
		SCT_DELETE(mThd);

		SCT_DELETE(mMutex);
		SCT_DELETE(mRTSPClient);

		while(!mData.empty())
		{
			CDataItem*p = mData.front();
			mData.pop_front();

			CDataItem::freeDataItem(p);
		}
	}

	void setUrl(const char * url)
	{
		CAutoLock locker(mMutex);

		mRTSPClient->setServerUrl(url);
	}

	int getData(void * p, const int max)
	{
		int ret = 0;

		CAutoLock locker(mMutex);

		if(mData.empty())
		{
			return 0;
		}

		CDataItem * item = mData.front();
		ret = item->len;

		memcpy(p, item->data, ret);

		CDataItem::freeDataItem(item);
		mData.pop_front();

		return ret;
	}

protected:
	virtual int main(CThread * caller)
	{
		if(mThd == caller)
		{
			rtsp(this);
		}
		return 0;
	}
private:
	static void* rtsp(void* p)
	{
		CMediaSource*self = (CMediaSource*)p;

		while(self->mState)
		{
			self->mRTSPClient->demux();
		}

		return NULL;
	}

private:
	CRTSPClientInterface * mRTSPClient;

	std::list<CDataItem*> mData;
	CMutex* mMutex;

	CThread * mThd;
	int mState;
};


class CRtspJni
{
public:
	CMediaSource * mSource;
};

static CRtspJni * gRtspJni = NULL;

JNIEXPORT void JNICALL Java_com_sct_rtsp_RTSPJni_create
  (JNIEnv *, jclass)
{
	if(NULL != gRtspJni)
	{
		SCT_LOGD();
		return;
	}

	gRtspJni = new CRtspJni;
	gRtspJni->mSource = new CMediaSource;
}

JNIEXPORT void JNICALL Java_com_sct_rtsp_RTSPJni_destroy
  (JNIEnv *, jclass)
{
	SCT_DELETE(gRtspJni->mSource);
	SCT_DELETE(gRtspJni);
}

JNIEXPORT jint JNICALL Java_com_sct_rtsp_RTSPJni_getData
  (JNIEnv * env, jclass, jbyteArray buf0, jint n)
{
	jint ret = 0;

	jbyte* p = env->GetByteArrayElements(buf0, 0);

	ret = gRtspJni->mSource->getData(p, n);

	env->ReleaseByteArrayElements(buf0, p, 0);
	return ret;
}

JNIEXPORT void JNICALL Java_com_sct_rtsp_RTSPJni_setUrl
  (JNIEnv *env, jclass, jstring url)
{
	const char * str = env->GetStringUTFChars(url, 0);

	gRtspJni->mSource->setUrl(str);

	env->ReleaseStringUTFChars(url, str);
}
